package net.esj.basic.validate.defaults;

import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.Map.Entry;

import javax.annotation.PostConstruct;
import javax.validation.Configuration;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.metadata.BeanDescriptor;

import net.esj.basic.utils.Validators;
import net.esj.basic.utils.i18n.LocaleUtils;

import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.HibernateValidatorConfiguration;

import com.opensymphony.xwork2.util.LocalizedTextUtil;

public class DefaultJSR303Validator implements Validator{

	Configuration<HibernateValidatorConfiguration> config;
	
	ValidatorFactory  validatorFactory;
	
	Validator validator;
	
	private static final String KEY_ENTITY_PROPERTY_EXPRESSION = "{$}";
	
	private static final String KEY_ENTITY_PROPERTY_REGEX = "\\{\\$\\}";
	
	private static final String KEY_ENTITY_PROPERTY_POSTFIX = "title";
	
	private static final String KEY_PREFIX_MATCHING = "{";
	
	private static final String KEY_POSTFIX_MATCHING = "}";
	
	@PostConstruct
	private void init(){
		config = Validation.byProvider(HibernateValidator.class).configure();
		config.messageInterpolator(new EntityMessageInterpolator(config.getDefaultMessageInterpolator()));
		validatorFactory = config.buildValidatorFactory();
		validator = validatorFactory.getValidator();
		//TODO 自定义message
	}

	public Validator getValidator() {
		return validator;
	}

	@Override
	public BeanDescriptor getConstraintsForClass(Class<?> arg0) {
		return validator.getConstraintsForClass(arg0);
	}

	@Override
	public <T> T unwrap(Class<T> arg0) {
		return validator.unwrap(arg0);
	}

	@Override
	public <T> Set<ConstraintViolation<T>> validate(T arg0, Class<?>... arg1) {
		return validator.validate(arg0, arg1);
	}

	@Override
	public <T> Set<ConstraintViolation<T>> validateProperty(T arg0,
			String arg1, Class<?>... arg2) {
		return validator.validateProperty(arg0, arg1, arg2);
	}

	@Override
	public <T> Set<ConstraintViolation<T>> validateValue(Class<T> arg0,
			String arg1, Object arg2, Class<?>... arg3) {
		return validator.validateValue(arg0, arg1, arg2, arg3);
	}
	
	/**
	 * 将{$}符号替换为对应对象的name  eg: net.esj.pojo.User.name
	 * @param <T>
	 * @param cv
	 * @param locale
	 * @return
	 */
	public static <T> Entry  decipherValidateMessageInI18N(ConstraintViolation<T> cv,Locale locale){
		String message = cv.getMessage();
		//String annotName = ((Annotation)cv.getConstraintDescriptor().getAnnotation()).annotationType().getName();
		
		
		
		if(message.indexOf(KEY_ENTITY_PROPERTY_EXPRESSION)>=0){
			
			ResourceBundle rb = LocalizedTextUtil.findResourceBundle(cv.getLeafBean().getClass().getName(), locale);
			
			String entityName = "";
			
			if(rb!=null){
				entityName = rb.getString(cv.getPropertyPath()+"."+KEY_ENTITY_PROPERTY_POSTFIX);
			}
			
			if(Validators.isEmpty(entityName)){
				entityName = LocaleUtils.getMessage(cv.getLeafBean().getClass().getName()+"."+cv.getPropertyPath(), locale);
			}
			message = message.replaceAll(KEY_ENTITY_PROPERTY_REGEX, entityName);
			
		}
		
		if(message.indexOf(KEY_PREFIX_MATCHING)>=0){
			String key = message.substring(message.indexOf(KEY_PREFIX_MATCHING)+1, message.lastIndexOf(KEY_POSTFIX_MATCHING));
			ResourceBundle rb = LocalizedTextUtil.findResourceBundle(cv.getLeafBean().getClass().getName(), locale);
			 	
			String submsg = "";
			
			if(rb!=null){
				submsg = rb.getString(key);
			}
			
			message = message.replace(KEY_PREFIX_MATCHING+key+KEY_POSTFIX_MATCHING, submsg);
		}
		
		return new ValidateEntry(cv.getPropertyPath().toString(), message);
	}
	
	public static class ValidateEntry implements Entry{
		
		private Object key;
		private Object value;

		public ValidateEntry(Object key, Object value) {
			super();
			this.key = key;
			this.value = value;
		}

		public ValidateEntry() {
			super();
		}

		@Override
		public Object getKey() {
			return key;
		}

		@Override
		public Object getValue() {
			return value;
		}

		@Override
		public Object setValue(Object value) {
			return value;
		}
		
	}
}
